#pragma once

#include "Socket.hpp"
#include "Logger.hpp"
#include <memory>
#include <poll.h>

static const int gsize = 1024;
static const int gdefault = -1;

class PollServer
{
public:
    PollServer(uint16_t port)
        : _listensockfd(std::make_unique<TcpSocket>())
    {
        // 创建监听套接字
        _listensockfd->BuildListenSocket(port);
        // 初始化数组
        for (int i = 0; i < gsize; i++)
        {
            fd_array[i].fd = gdefault;
            fd_array[i].events = fd_array[i].revents = 0;
        }
        // 将套接字信息放在数组下标为0的位置上
        fd_array[0].fd = _listensockfd->Sockfd();
        fd_array[0].events = POLLIN; // 关系其读事件
    }
    ~PollServer() {}
    void Accepter()
    {
        // 获取连接
        InetAddr client;
        int sockfd = _listensockfd->Accept(&client);
        if (sockfd > 0)
        {
            LOG(LogLevel::DEBUG) << "获取到一个新连接：" << sockfd << ",client :" << client.ToString();
            // 加入数组中
            // 遍历数组找到一个空位
            int i = 0;
            for (; i < gsize; i++)
            {
                if (fd_array[i].fd == gdefault)
                {
                    fd_array[i].fd = sockfd;
                    fd_array[i].events = POLLIN; // 关心其读事件
                    break;
                }
            }

            // 如果没有找到就说明满了，可以进行扩容处理；如果底层为指针的话
            if (i >= gsize)
            {
                LOG(LogLevel::ERROR) << "服务器满载";
            }
        }
    }
    void Recver(int index)
    {
        // 获取数据
        int sockfd = fd_array[index].fd;
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        // 判断其返回值
        if (n > 0)
        {
            // 读取数据成功
            buffer[n] = 0;
            // debug
            std::cout << "client say# " << buffer << std::endl;
            // 构建应答
            std::string send_str = "server say#";
            send_str += buffer;
            // 直接调用send 返回
            send(sockfd, send_str.c_str(), send_str.size(), 0);
        }
        else if (n == 0)
        {
            LOG(LogLevel::DEBUG) << "对端关闭，服务端也关闭， sockfd： " << sockfd;
            // 返回值为0代表独对端关闭，将此文件描述符从数组中移除，并将events 和 revents 置空
            fd_array[index].fd = gdefault;
            fd_array[index].events = fd_array[index].revents = 0;
            // 还需要关闭文件描述符
            close(sockfd);
        }
        else
        {
            // 读失败也是
            LOG(LogLevel::DEBUG) << "读取失败";
            fd_array[index].fd = gdefault;
            fd_array[index].events = fd_array[index].revents = 0;
            close(sockfd);
        }
    }
    void EventDispathcher()
    {
        // 派发任务,遍历数组判断哪些任务已经就绪了
        for (int i = 0; i < gsize; i++)
        {
            if (fd_array[i].fd == gdefault)
            {
                continue;
            }

            // 需要判断其读事件是否就绪
            if (fd_array[i].revents & POLLIN)
            {

                // 合法的文件描述符
                // 判断是监听套接字还是普通的文件描述符
                if (fd_array[i].fd == _listensockfd->Sockfd())
                {
                    // 调用获取连接模块
                    Accepter();
                }
                else
                {
                    // 读模块
                    Recver(i);
                }
            }
        }
    }
    // 运行
    void Run()
    {
        // 不能直接获取连接，而是将交给poll
        //  int poll(struct pollfd *fds, nfds_t nfds, int timeout);
        // poll 的返回值判断：0 ， 表示没有一个文件描述符就绪；大于0，表示有n个事件就绪；小于0，意味着出错
        while (true) // 循环检测
        {
            int timeout = 1000; // 单位为毫秒
            int n = poll(fd_array, gsize, timeout);
            // if(n == 0)
            // {
            //     LOG(LogLevel::INFO) << "事件未就绪";
            // }
            // else if(n < 0)
            // {
            //     //出错
            //     LOG(LogLevel::WARNING) << "poll 出错";
            // }
            // else{
            //     //有事件就绪
            //     EventDispathcher();
            // }
            switch (n)
            {
            case 0:
                LOG(LogLevel::INFO) << "事件未就绪";
                break;
            case -1:
                LOG(LogLevel::WARNING) << "poll 出错";
                break;
            default:
                EventDispathcher();
                break;
            }
        }
    }

private:
    std::unique_ptr<Socket> _listensockfd;
    struct pollfd fd_array[gsize];
    //     struct pollfd
    //   {
    //     int fd;			/* File descriptor to poll.  */ 文件描述符
    //     short int events;		/* Types of events poller cares about.  */ 用户告诉系统需要关心的文件描述符
    //     short int revents;		/* Types of events that actually occurred.  */ 系统告诉用户哪些文件描述符准备好了
    //   };
};